#include <vector>
#include <list>
#include <string>
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <memory>
#include "bits.hpp"
#include "array.hpp"
#include "digit_mask.hpp"
#include "vector.hpp"
using namespace std;

#define ADD_TIMES 40000
#define DEL_TIMES 30000
#define READ_TIMES 20000
#define INSERT_TIMES 500
#define RANDOM_INT(__val__) rand() % __val__

void digitInfo( DigitMask const& dm ) {
    cout << "digit:" << dm.range() << endl;
    for ( size_t i = 0; i < dm.range(); i++ ) {
        cout << dm[i] << ",";
    }
    cout << endl << endl;
}
void testDigitMask() {
    {
        DigitMask dm( 16 );
        dm.toggle( 0 ).toggle( 1 ).toggle( 8 );

        digitInfo( dm );

    }
    double start = clock();
    DigitMask dm2048( 2048 );
    {
        size_t range = dm2048.range();
        for ( int i = 0; i < 1000000; i++ ) {
            dm2048.toggle( RANDOM_INT( range ) );
        }
    }
    double end = clock();
    digitInfo( dm2048 );
    cout << "random toggle 1,000,000 cost:" << ( end - start ) / CLOCKS_PER_SEC << endl;


    {
        DigitMask dm( 8 );
        digitInfo( dm );
        dm.insert( 4, Bit8::BIT_VAL::ONE );
        digitInfo( dm );
        dm.insert( 4, Bit8::BIT_VAL::ONE );
        digitInfo( dm );
        dm.insert( 4, Bit8::BIT_VAL::ZERO );
        digitInfo( dm );
        dm.insert( 4, Bit8::BIT_VAL::ONE );
        digitInfo( dm );
        dm.clean();
        digitInfo( dm );
    }


    cin.get();
};
template <typename T>
void vectorInfo( Vector<T> const& vec ) {
    cout << "vector:" << vec.count() << endl;
    for ( int i = 0; i < vec.count(); i++ ) {
        cout << vec[i];
    }
    cout << endl << endl;
}
void performanceVector() {
    cout << endl;
    cout << "---Vector:" << endl;
    double start = clock();
    Vector<int> mv;
    for ( size_t i = 0; i < ADD_TIMES; i++ ) {
        mv.push( RANDOM_INT( 1000 ) );
    }

    double addTime = clock();
    {
        size_t count = mv.count();
        for ( size_t i = 0; i < DEL_TIMES; i++ ) {
            mv.del( RANDOM_INT( count ) );
            count--;
        }

    }
    double delTime = clock();

    {
        size_t count = mv.count();
        for ( size_t i = 0; i < INSERT_TIMES; i++ ) {
            mv.insert( RANDOM_INT( count ), RANDOM_INT( 1000 ) );
            count++;
        }

    }
    double insertTime = clock();
    {
        size_t count = mv.count();
        int sum = 0;
        for ( size_t i = 0; i < READ_TIMES; i++ ) {
            sum += mv[RANDOM_INT( count )];
        }
    }
    double readTime = clock();


    cout << "addTime:" << ( addTime - start ) / CLOCKS_PER_SEC << " delTime:" << ( delTime - addTime ) / CLOCKS_PER_SEC << " insertTime:" << ( insertTime - delTime ) / CLOCKS_PER_SEC << " readTime:" << ( readTime - insertTime ) / CLOCKS_PER_SEC << endl;

    cout << "press any key to continue..." << endl;
    cin.get();

};
void performanceStdVector() {
    cout << endl;
    cout << "---std::vector:" << endl;
    double start = clock();
    vector<int> vec;
    for ( size_t i = 0; i < ADD_TIMES; i++ ) {
        vec.push_back( RANDOM_INT( 1000 ) );
    }

    double addTime = clock();

    for ( size_t i = 0; i < DEL_TIMES; i++ ) {
        vec.erase( vec.begin() + ( RANDOM_INT( vec.size() ) ) );
    }

    double delTime = clock();

    size_t count = vec.size();
    for ( size_t i = 0; i < INSERT_TIMES; i++ ) {
        vec.insert( vec.begin() + RANDOM_INT( count ), RANDOM_INT( 1000 ) );
        count++;
    }

    double insertTime = clock();
    {
        size_t count = vec.size();
        int sum = 0;
        for ( size_t i = 0; i < READ_TIMES; i++ ) {
            sum += vec[RANDOM_INT( count )];
        }
    }
    double readTime = clock();

    cout << "addTime:" << ( addTime - start ) / CLOCKS_PER_SEC << " delTime:" << ( delTime - addTime ) / CLOCKS_PER_SEC << " insertTime:" << ( insertTime - delTime ) / CLOCKS_PER_SEC << " readTime:" << ( readTime - insertTime ) / CLOCKS_PER_SEC << endl;

    cout << "press any key to continue..." << endl;
    cin.get();
};

template <typename T>
void infoArray( Array<T> & arr ) {
    size_t count = arr.count();
    cout << "array:" << count << endl;
    for ( size_t i = 0; i < count; i++ ) {
        int a = arr[i];
        cout << a << ",";
    }
    cout << endl << endl;
}
void testArray() {
    Array<int> arr;
    infoArray( arr );
}
void performanceArray() {
    cout << endl;
    cout << "---Array:" << endl;
    double start = clock();
    Array<int> mv;
    for ( size_t i = 0; i < ADD_TIMES; i++ ) {
        mv.push( RANDOM_INT( 1000 ) );
    }

    double addTime = clock();
    {
        size_t count = mv.count();
        for ( size_t i = 0; i < DEL_TIMES; i++ ) {
            mv.del( RANDOM_INT( count ) );
            count--;
        }

    }
    double delTime = clock();
    double insertTime = clock();
    try
    {
        size_t count = mv.count();
        for ( size_t i = 0; i < INSERT_TIMES; i++ ) {
            mv.insert( RANDOM_INT( count ), RANDOM_INT( 1000 ) );
            count++;
        }
    }
    catch ( char const* e ) {
        cout << "insert:" << e << endl;
    }
    insertTime = clock();

    double readTime = clock();
    try
    {
        size_t count = mv.count();
        int sum = 0;
        for ( size_t i = 0; i < READ_TIMES; i++ ) {
            sum += mv[RANDOM_INT( count )];
        }
    }
    catch ( char const* e ) {
        cout << "read:" << e << endl;
    }
    readTime = clock();


    cout << "addTime:" << ( addTime - start ) / CLOCKS_PER_SEC << " delTime:" << ( delTime - addTime ) / CLOCKS_PER_SEC << " insertTime:" << ( insertTime - delTime ) / CLOCKS_PER_SEC << " readTime:" << ( readTime - insertTime ) / CLOCKS_PER_SEC << endl;

    cout << "press any key to continue..." << endl;
    cin.get();
}
void performance() {
    cout << "add " << ADD_TIMES << endl;
    cout << "random del " << DEL_TIMES << endl;
    cout << "random insert " << INSERT_TIMES << endl;
    cout << "random read " << READ_TIMES << endl;
    performanceStdVector();
    performanceVector();
    performanceArray();
}

int main( int argc, char* argv[] ) {
    //testArray();
    performance();
    cin.get();
    return 0;
}